﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace System.Windows.Controls
{
    /// <summary>
    /// Implements a base class for use in various <see cref="System.Windows.Controls.ItemsControl"/> derived implementations.
    /// </summary>
    [TemplateVisualState(Name="Normal", GroupName="CommonStates")]
    [TemplateVisualState(Name="MouseOver", GroupName="CommonStates")]
    [TemplateVisualState(Name="Pressed", GroupName="CommonStates")]
    [TemplateVisualState(Name="Disabled", GroupName="CommonStates")]
    [TemplateVisualState(Name="Focused", GroupName="FocusStates")]
    [TemplateVisualState(Name="Unfocused", GroupName="FocusStates")]
    public class ItemControl : System.Windows.Controls.ContentControlBase
    {
        /// <summary>
        /// Instantiates a <see cref="ItemControl"/> instance.
        /// </summary>
        public ItemControl()
        {
            this.Loaded += new RoutedEventHandler(OnLoaded);            
        }

        private SelectionItemsControl    _ParentItemsControl = null;

        /// <summary>
        /// Identifies the <see cref="IsSelected"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty   IsSelectedProperty = RegisterDependencyProperty(typeof(ItemControl), "IsSelected", typeof(bool));

        /// <summary>
        /// (Override) Handles custom dependency property changes for this control.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDependencyPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.Property == IsSelectedProperty)
            {
                this.IsSelected = (bool)e.NewValue;
            }
            else
            {
                base.OnDependencyPropertyChanged(e);
            }
        }

        /// <summary>
        /// Gets/Sets a boolean value indicating whether this <see cref="ItemControl"/> is currently selected.
        /// </summary>
        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set 
            { 
                SetValue(IsSelectedProperty, value); 
                GoToState(true, (value ? "Pressed" : "Normal"));
                OnIsSelectedChanged(value);
            }
        }

        /// <summary>
        /// Gets a reference to the <see cref="SelectionItemsControl"/> parent for this <see cref="ItemControl"/>.
        /// </summary>
        public SelectionItemsControl ParentItemsControl
        {
            get { return _ParentItemsControl; }
            internal set { _ParentItemsControl = value; }
        }

        /// <summary>
        /// Implements a virtual handler for handling the Loaded event. This method fires when the <see cref="ItemControl"/> has been added to the visual tree.
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> argument for the event</param>
        protected virtual void OnLoaded(object sender, RoutedEventArgs e)
        {
            if (this.IsSelected)
            {
                GoToState(true, "Pressed");
            }
        }

        /// <summary>
        /// (Override) Handles the Mouse Enter event for the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> for the event</param>
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            base.OnMouseEnter(e);
            if (this.IsEnabled && !this.IsSelected) GoToState(true, "MouseOver");
        }

        /// <summary>
        /// (Override) Handles the Mouse Leave event for the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> for the event</param>
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            base.OnMouseLeave(e);
            if (this.IsEnabled && !this.IsSelected) GoToState(true, "Normal");
        }

        /// <summary>
        /// (Override) Handles the Mouse Left Button Down event for the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> for the event</param>
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);
            if (this.IsEnabled && !this.IsSelected)
            {
                this.CaptureMouse();
                GoToState(true, "Pressed");
            }
        }

        /// <summary>
        /// (Override) Handles the Mouse Left Button Up event for the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> for the event</param>
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);
            if (this.IsEnabled && !this.IsSelected)
            {
                Point pt = e.GetPosition(this);
                this.ReleaseMouseCapture();

                if (this.ClientRect.Contains(pt))
                {
                    if (this.ParentItemsControl != null) this.ParentItemsControl.ChangeSelection(this, true);
                }
                else
                {
                    GoToState(true, "Normal");
                }
            }
        }

        /// <summary>
        /// (Override) Handles the Got Focus event for the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> for the event</param>
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
            if (this.IsTabStop) GoToState(true, "Focused");
        }

        /// <summary>
        /// (Override) Handles the Lost Focus event for the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> for the event</param>
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);
            if (this.IsTabStop) GoToState(true, "Unfocused");
        }

        /// <summary>
        /// (Override) Handles the changes to the enablement of the <see cref="ItemControl"/>.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> for the event</param>
        protected override void OnIsEnabledChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnIsEnabledChanged(e);
            GoToState(true, (this.IsEnabled ? "Normal" : "Disabled"));
        }

        /// <summary>
        /// A virtual method which is called when the <see cref="ItemControl"/> IsSelected property changes
        /// </summary>
        /// <param name="selected">A boolean which specifies the new value of <see cref="IsSelected"/></param>
        protected virtual void OnIsSelectedChanged(bool selected)
        {

        }
    }

    /// <summary>
    /// Implements an event argument type for identifiying an <see cref="System.Windows.Controls.ItemControl"/> instance
    /// </summary>
    public class ItemControlEventArgs : EventArgs
    {
        /// <summary>
        /// A reference to the <see cref="System.Windows.Controls.ItemControl"/> instance.
        /// </summary>
        public readonly ItemControl     Control = null;

        /// <summary>
        /// Instantiates the <see cref="ItemControlEventArgs"/> instance.
        /// </summary>
        /// <param name="control">The <see cref="System.Windows.Controls.ItemControl"/> instance for the event</param>
        public ItemControlEventArgs(ItemControl control)
        {
            this.Control = control;
        }
    }
}
